/**
 * com.monte.tools.GenerateSelect4Jpa.java
 * add by FengMy
 */
package com.monte.tools;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import com.monte.entity.CoreEntity;
import com.monte.entity.DataEntity;
import com.monte.permission.model.PermissionItem;
import com.monte.util.StringUtils;

/**
 * 描述：根据主对象生成查询sql
 * @author FengMy
 * @since 2013-9-9 
 */
public class GenerateSelect4Jpa {
	private static final Class<?> CLAZZ= PermissionItem.class;
	
	public static void main(String[] args) {
		Entity entity = (Entity) CLAZZ.getAnnotation(Entity.class);
		if(entity == null){
			throw new RuntimeException(CLAZZ.getName()+" is not a entity class.");
		}
		if(!CoreEntity.class.isAssignableFrom(CLAZZ)){
			throw new RuntimeException("目前仅支持CoreEntity的子类型");
		}
		List<Field> fields = getFields(CLAZZ);
		Map<Field,String> alias = getEntityAlias(fields);
		List<String> selectors = getSelectFields(fields, alias);
		List<String> froms = getFroms(alias);
		
		StringBuffer sql = new StringBuffer();
		sql.append("SELECT").append("\n");
		for(int i = 0; i < selectors.size(); i++){
			sql.append(selectors.get(i));
			if(i < selectors.size() - 1){
				sql.append(",");
			}
			sql.append("\n");
		}
		sql.append("FROM " + getTableByEntityClass(CLAZZ)).append(" A").append("\n");
		for(String s : froms){
			sql.append(s).append("\n");
		}
		System.out.println(sql.toString());
	}
	
	
	
	/**
	 * 从表信息
	 * @param alias
	 * @return
	 */
	private static List<String> getFroms(Map<Field,String> alias){
		List<String> froms = new LinkedList<String>();
		Set<Field> fields = alias.keySet();
		for(Field f : fields){
			froms.add("LEFT JOIN " + getTableByEntityClass(f.getType()) + " " + alias.get(f) + " ON A." + getColumnName(f) + " = " + alias.get(f) + ".FID");
		}
		return froms;
	}
	
	/**
	 * 获取外键关联表别名
	 * @param fields
	 * @return
	 */
	private static Map<Field,String> getEntityAlias(List<Field> fields){
		Map<Field,String> alias = new HashMap<Field, String>();
		char a = 'B';//主表为A，其它关联表从B起
		for(Field f : fields){
			Class<?> fType = f.getType();
			if(CoreEntity.class.isAssignableFrom(fType)){
				alias.put(f, String.valueOf(a));
				a = (char) (a+1);
			}
		}
		return alias;
	}
	
	/**
	 * 根据类名获取表名
	 * @param clazz
	 * @return
	 */
	private static String getTableByEntityClass(Class<?> clazz){
		Entity entity = (Entity) clazz.getAnnotation(Entity.class);
		if(entity == null || StringUtils.isEmpty(entity.name())){
			return clazz.getSimpleName().toUpperCase();
		}
		return entity.name().toUpperCase();
	}
	
	/**
	 * 获取查询字段列表
	 * @param fields
	 * @return
	 */
	private static List<String> getSelectFields(List<Field> fields,Map<Field,String> alias){
		List<String> selectors = new LinkedList<String>();
		for(Field f : fields){
			 if(isSimpleType(f)){
				 selectors.add("A." + getColumnName(f) + " AS " + "\""+f.getName()+"\"");
			 }
			 if(CoreEntity.class.isAssignableFrom(f.getType())){
				 selectors.add(alias.get(f) + ".FID" + " AS " + "\""+f.getName()+".id\"");
				 if(DataEntity.class.isAssignableFrom(f.getType())){
					 selectors.add(alias.get(f) + ".FNAME" + " AS " + "\""+f.getName()+".name\"");
					 selectors.add(alias.get(f) + ".FNUMBER" + " AS " + "\""+f.getName()+".number\"");
				 }
			 }
		}
		return selectors;
	}
	
	/**
	 * 获取字段名
	 * @param field
	 * @return
	 */
	private static String getColumnName(Field field){
		JoinColumn jc = field.getAnnotation(JoinColumn.class);
		if(jc != null && !StringUtils.isEmpty(jc.name())){
			//外键
			return jc.name().toUpperCase();
		}
		Column cl = field.getAnnotation(Column.class);
		if(cl != null && !StringUtils.isEmpty(cl.name())){
			//字段名
			return cl.name().toUpperCase();
		}
		return field.getName().toUpperCase();
	}
	
	/**
	 * 字段类型是否普通类型(基本数据类型,字符串，枚举)
	 * @param field
	 * @return
	 */
	private static boolean isSimpleType(Field field){
		if(field.isEnumConstant()){//枚举
			return true;
		}
		Class<?> fieldType = field.getType();
		if(//字符串或者基本数据类型
				 fieldType == String.class
 			   || fieldType == Character.class
 			   || fieldType == Boolean.class
			   || Number.class.isAssignableFrom(fieldType)
			){
			return true;
		}
		return false;
	}
	
	/**
	 * 获取类上所有持久化属性(包括父类)
	 * @param clazz
	 * @return
	 */
	private static List<Field> getFields(Class<?> clazz){
		List<Field> fields = new LinkedList<Field>();
		if(clazz.getSuperclass() != null && clazz != CoreEntity.class){
			fields.addAll(getFields(clazz.getSuperclass()));
		}
		Field[] fs = clazz.getDeclaredFields();
		for(Field f : fs){
			if(is(f, Modifier.STATIC) || is(f,Modifier.FINAL)){
				//静态变量和最终变量不处理
				continue;
			}
			Transient tran = f.getAnnotation(Transient.class);
			if(tran != null){
				//非持久化字段不处理
				continue;
			}
			OneToMany otm = f.getAnnotation(OneToMany.class);
			if(otm != null){
				//一对多字段不作处理
				continue;
			}
			fields.add(f);
		}
		return fields;
	}
	
	/**
	 * 判断字段的修饰符
	 * @param f
	 * @param t
	 * @return
	 */
	private static boolean is(Field f,int t){
		return (f.getModifiers() & t) == t;
	}

}
